package com.ddf.entity;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * @author DDf on 2018/8/19
 * @Entity 代表这是一个映射实体,使用名称指定映射的表名
 * @see META-INF/persistence.xml
 */
@Table(name = "USER")
@Entity
@Cacheable
public class User {
    private Integer id;
    private String username;
    private String password;
    private Date birthDay;
    private Date createTime;
    private Date modifyTime;
    private String message;
    private Set<Order> orderList = new HashSet<>();
    private IdCard idCard;

    public User() {

    }

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public User(String username, String password, Date birthDay, Date createTime, Date modifyTime) {
        this.username = username;
        this.password = password;
        this.birthDay = birthDay;
        this.createTime = createTime;
        this.modifyTime = modifyTime;
    }

    /**
     * @Id 主键列
     * @GeneratedValue 自动生成数据列
     * @GenericGenerator 主键生成策略 increment使用hibernate的自增长策略，会自动在数据库中创建维护seq的一张表
     *
     * IDENTITY 采用数据库 ID自增长的方式来自增主键字段，Oracle 不支持这种方式；
     * AUTO： JPA自动选择合适的策略，是默认选项；
     * SEQUENCE：通过序列产生主键，通过 @SequenceGenerator 注解指定序列名，MySql 不支持这种方式
     * TABLE：通过表产生主键，框架借由表模拟序列产生主键，使用该策略可以使应用更易于数据库移植。
     * @return
     */
    @Id
    @GeneratedValue
    @GenericGenerator(name="increment", strategy = "increment")
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }


    /**
     * @Column 将数据库字段与实体字段做映射常
     * columnDefinition 表示该字段在数据库中的实际类型,ORM 框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据
     * 库中字段类型究竟是DATE,TIME还是TIMESTAMP.此外,String的默认映射类型为VARCHAR, 如果要将 String 类型映射到特定数据库的
     * BLOB 或TEXT 字段类型.
     * @return
     */
    @Column(name = "USER_NAME")
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Column(name = "PASSWORD")
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * @Temporal 用来区分Date数据精度
     * @return
     */
    @Column(name = "BIRTH_DAY")
    @Temporal(value = TemporalType.DATE)
    public Date getBirthDay() {
        return birthDay;
    }

    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

    /**
     * @Temporal 用来区分Date数据精度
     * @return
     */
    @Column(name = "CREATE_TIME")
    @Temporal(value = TemporalType.TIMESTAMP)
    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * @Temporal 用来区分Date数据精度
     * @return
     */
    @Column(name = "MODIFY_TIME")
    @Temporal(value = TemporalType.TIMESTAMP)
    public Date getModifyTime() {
        return modifyTime;
    }

    public void setModifyTime(Date modifyTime) {
        this.modifyTime = modifyTime;
    }

    /**
     * @Transient 默认实体字段与表名字段无法映射使会报错，这个注解表示当前字段无需与数据库字段做映射
     * @return
     */
    @Transient
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }


    /**
     * 可以通过修改fetch属性，来更改其它表的加载属性，默认为懒加载，当使用Order的时候，再单表查询Order，如果改为
     * fetch = FetchType.EAGER 则查询user会直接Left outer join Order
     * @return
     */
    @OneToMany(targetEntity = Order.class, mappedBy = "user", fetch = FetchType.LAZY)
    public Set<Order> getOrderList() {
        return orderList;
    }

    public void setOrderList(Set<Order> ordersList) {
        this.orderList = ordersList;
    }

    /**
     * one to one的映射默认加载不是懒加载，而是会在查询User Left join IdCard两张表的数据都取出来
     * 可以通过fetch属性来更改为懒加载，但是改为懒加载之后，第一次查询User单表，之后依然会在发出Sql查询IdCard。
     * 如果IdCard那里fetch属性为EAGER，则会IdCard left join User， 查询两张表的数据，而如果改为懒加载，则第二次依然会发出查询
     * IdCard的sql,只不过这一次是单表查询
     * @return
     */
    @OneToOne(mappedBy = "user", fetch = FetchType.EAGER)
    public IdCard getIdCard() {
        return idCard;
    }

    public void setIdCard(IdCard idCard) {
        this.idCard = idCard;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthDay=" + birthDay +
                ", createTime=" + createTime +
                ", modifyTime=" + modifyTime +
                ", message='" + message + '\'' +
                '}';
    }
}
